#include "main.h"
#include <stdio.h>
#include <stdint.h>
#include "my_uart_app.h"
#include "sys_param.h"

#define  FLASH_PAGE_SIZE               0x800     // 2 Kbytes

#define  APPLICATION_ADDRESS           (uint32_t)0x8006800              //APP_START_ADDRESS
#define  BOOT_PARA_ADDRESS             (APPLICATION_ADDRESS- (0x800))   //update_flag
/* APP flash相关宏定义 */
#define UPDATE_APP_FLAG                ((uint32_t)0x67890123)           //从BootLoader para区读到此值，表示APP需要更新

uint32_t tmp_data = UPDATE_APP_FLAG;

extern void Delay(uint32_t count);

/******************************************************************************
* FunctionName : Cal_CRC16 IAP上位机对应的crc校验方法
* Description : CRC校验
* EntryParameter : None
* ReturnValue : None
******************************************************************************/
uint16_t Cal_CRC16(const uint8_t* pu8Data, uint32_t u32Len)
{
    uint8_t i;
    uint16_t crc = 0xA28C;        // Initial value
    while(u32Len--)
    {
        crc ^= *pu8Data++;            // crc ^= *data; data++;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0x8408;        // 0x8408 = reverse 0x1021
            else
                crc = (crc >> 1);
        }
    }
    return ~crc;                // crc^Xorout
}

/*******************************************************************************
 * 国民技术芯片，循环写入，数据len(为 u32位数据长度的len)   my_flash_write_32_data((uint32_t *)BOOT_PARA_ADDRESS, &tmp_data, 1);
 ******************************************************************************/
static int my_flash_write_32_data(uint32_t *p_Address, uint32_t* p_Data, uint32_t len)
{
    int i;
  
    for(i = 0; i < len; i++){
    // **************如果地址是新page页，则先擦除page
        if((*p_Address)%FLASH_PAGE_SIZE == 0){
            FLASH_Unlock();
            FLASH_EraseOnePage((*p_Address));
        }
        // 写入4个字节的数据，一次写入4个byte后，地址向后 偏移4byte
        printf("read_flash aa :0x%0x \r\n ", (*(__IO uint32_t*)(0x8006800- 0x800)));
        printf("Flash write addr:[0x%0x]--data:[0x%0x] \r\n", (*p_Address), *p_Data);
        FLASH_ProgramWord((*p_Address), *p_Data);

        // FLASH_ProgramWord((*((uint32_t *)BOOT_PARA_ADDRESS)), *p_Data);
        printf("read_flash bb :0x%0x \r\n ", (*(__IO uint32_t*)(0x8006800- 0x800)));
        // printf("flash_read_write aa:0x%0x \r\n", *((uint32_t *)p_Address));
        // printf("flash_read_write bb:0x%0x \r\n", *((uint32_t *)BOOT_PARA_ADDRESS));
        printf("flash_read_write aa:0x%0x \r\n", *((__IO uint32_t *)p_Address));
        printf("flash_read_write bb:0x%0x \r\n", *((__IO uint32_t *)BOOT_PARA_ADDRESS));
        printf("read_flash cc :0x%0x \r\n ", (*(__IO uint32_t*)(0x8006800- 0x800)));
        *p_Address += 4;
        p_Data ++;
        // test_dataaa = *p_Data;
    }



	return 0;
}

//***************************************************
// flash 存储
//   flash升级标记位
//***************************************************
static void writer_iap_updat_flag_to_flash(void)
{
    uint32_t tmp_addr, i;
    // int write_data_flag = 0;
    uint32_t WRPR_Value = 0xFFFFFFFF, ProtectedPages = 0, ProgramData = 0xFFFFFF;
    
 
    //---------------------------------   
    /* Program FLASH */
    /* Configures the Internal High Speed oscillator */
    if(FLASH_HSICLOCK_DISABLE == FLASH_ClockInit())
    {
        printf("HSI oscillator not yet ready\r\n");
        while(1);
    }

    /* Unlocks the FLASH Program Erase Controller */
    FLASH_Unlock();

    /* Erase */
    if (FLASH_COMPL != FLASH_EraseOnePage(BOOT_PARA_ADDRESS))
    {
        while(1)
        {
            printf("Flash EraseOnePage Error. Please Deal With This Error Promptly\r\n");
        }
    }
 
    tmp_addr = BOOT_PARA_ADDRESS;
    my_flash_write_32_data(&tmp_addr, (uint32_t*)&tmp_data, 1);

    printf("flash_read_write:0x%0x \r\n", *((uint32_t *)BOOT_PARA_ADDRESS));
    // printf("Flash write notify:[%d]--power:[%d] \r\n", flash_param.bat_low_notify_flag, flash_param.bat_low_power_off_flag);
    FLASH_Lock();
   
    //---------------------------------     
}



/******************************************************************************
* FunctionName : crc16_compute(uint8_t const * p_data, uint32_t size, uint16_t const * p_crc)
* Description : CRC校验
* EntryParameter : None
* ReturnValue : None
******************************************************************************/
uint16_t crc16_compute(uint8_t const * p_data, uint32_t size)
{
    uint16_t crc =0xFFFF;
		int i;
    for (i = 0; i < size; i++)
    {
        crc = (uint8_t)(crc >> 8) | (crc << 8);
        crc ^= p_data[i];
        crc ^= (uint8_t)(crc & 0xFF) >> 4;
        crc ^= (crc << 8) << 4;
        crc ^= ((crc & 0xFF) << 4) << 1;
    }
    return crc;
}

/********************************************
 * 获取底座连接状态
 * 
 ***********************************************/
uint8_t get_base_connect_flag(void)
{

    return  uart_data.base_connect_flag;
}

/********************************************
 * 串口超时判断
 * 
 ***********************************************/
void my_uart_timeout_checkout(void)
{
    uart_data.unrecv_timeout_cnt ++;

    if(uart_data.unrecv_timeout_cnt > MAX_TIMEOUT_CNT){
            uart_data.unrecv_timeout_cnt = 0;
            if(uart_data.base_connect_flag){
                uart_data.base_connect_flag = 0;
            }
    }
}

/********************************************
 * 老化模式下，状态发送
 * 0xee 0x08 0x00 0x0f 0x00 0x00 crc_h  crc_l   //  主机在停止输出，在充电状态
   0xee 0x08 0x00 0x0f 0x00 0x00  0x2b  0x97

   0xee 0x08 0x00 0x0f 0x00 0x01 crc_h  crc_l   //  主机在停止充电，在输出状态
   0xee 0x08 0x00 0x0f 0x00 0x01 0x3b 0xb6
 ***********************************************/
void send_aling_mode_sta(void)
{
    uint16_t crc;

    if(ALIGN_STA != get_sys_state()){
        return;
    }

    uart_data.tx_buff[0] = 0xee;
    uart_data.tx_buff[1] = 0x08;
    uart_data.tx_buff[2] = 0x00;
    uart_data.tx_buff[3] = 0x0f;    // 老化指令

    uart_data.tx_buff[4] = 0x00;   // 电池信息应答

    if(sys_data.aling_run_cnt > ALING_MODE_MAX_OUT_TIME){
        uart_data.tx_buff[5] = 0x00;    // 充电中
    }
    else{
        uart_data.tx_buff[5] = 0x01;    // 充电完毕     
    }

    crc = crc16_compute(uart_data.tx_buff, 6);

    uart_data.tx_buff[6] = crc>>8;
    uart_data.tx_buff[7] = crc&0xff;

    uartx_send_data(8);
}
/**********
 *  * 主机发送：
     *      充电中  ：0xee 0x08 0x00 0x04 0x04 0x01 0x07 0x83
     *      充电完毕：0xee 0x08 0x00 0x04 0x04 0x02 0x37 0xe0
*/
void uart_send_normal_mode_sta(void)
{
    uint16_t crc;

    uart_data.tx_buff[0] = 0xee;
    uart_data.tx_buff[1] = 0x08;
    uart_data.tx_buff[2] = 0x00;
    uart_data.tx_buff[3] = 0x04;    // 电池相关指令

    uart_data.tx_buff[4] = 0x04;   // 电池信息应答

    if(CHARGE_STA == get_sys_state()){
        uart_data.tx_buff[5] = 0x01;    // 充电中
    }
    else{
        uart_data.tx_buff[5] = 0x02;    // 充电完毕     
    }


    crc = crc16_compute(uart_data.tx_buff, 6);

    uart_data.tx_buff[6] = crc>>8;
    uart_data.tx_buff[7] = crc&0xff;

    uartx_send_data(8);
}

uint8_t iap_shake_hands_ack_buff[] = {0x6D,0xAC,0x00,0xFF,0x0A,0x00,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCF,0x68};

/********************************************
 * 串口接收函数回调
 * 串口升级IAP,连接时，发送的第一包数据为：
 *  6D AC 01 FE 0A 00 26 11 00 00 00 00 00 00 00 00 A6 DA
 * //mcu回复：
 * {0x6D,0xAC,0x00,0xFF,0x0A,0x00,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCF,0x68};
 * 
 ***********************************************/
void my_uart_callback(void)
{
    uint16_t crc;
    int i;
    if(0 == uart_data.recv_flag){
        return;
    }

    uart_data.recv_flag = 0;
    if(uart_data.recv_num < 2){
        return;
    }
    if((uart_data.rx_buff[0] == 0x6D)&&(uart_data.rx_buff[1] == 0xAC)){

        memcpy(uart_data.tx_buff, iap_shake_hands_ack_buff, sizeof(iap_shake_hands_ack_buff));
        uartx_send_data(sizeof(iap_shake_hands_ack_buff));
        
        Delay(100);

        printf("flash_update_flag 111:0x%0x \r\n", *((uint32_t *)BOOT_PARA_ADDRESS));
        writer_iap_updat_flag_to_flash();
        // my_flash_write_32_data((uint32_t *)BOOT_PARA_ADDRESS, &tmp_data, 1);

        printf("flash_update_flag 222:0x%0x \r\n", *(uint32_t *)BOOT_PARA_ADDRESS);
        Delay(100);


        __NVIC_SystemReset();
        return;
    }



    if(0xff != uart_data.rx_buff[0]){
        //  printf("buff[%0x]  len[%d] \r\n", uart_data.rx_buff[0], uart_data.recv_num);
        uart_data.recv_num = 0;
        return;
    }

    crc = crc16_compute((uint8_t const *)uart_data.rx_buff, uart_data.recv_num - 2);
    if(crc != ((uart_data.rx_buff[uart_data.recv_num-2]<<8)|uart_data.rx_buff[uart_data.recv_num-1]))
    {
        return;
    }

    /********
     * 底座发过来的指令：ff 08 00 04 03 00 d1 11
     * 
     * 主机回复：
     *      充电中  ：0xee 0x08 0x00 0x04 0x04 0x01 0x07 0x83
     *      充电完毕：0xee 0x08 0x00 0x04 0x04 0x02 0x37 0xe0
     * 
     * */ 

    switch(uart_data.rx_buff[3])
    {
        case UART_BAT_CMD:{
            switch(uart_data.rx_buff[4]){
                case CHARGE_STA_REQ:{
                    uart_data.unrecv_timeout_cnt = 0;
                    uart_data.base_connect_flag = 1;
                    uart_data.tx_buff[0] = 0xee;
                    uart_data.tx_buff[1] = 0x08;
                    uart_data.tx_buff[2] = 0x00;
                    uart_data.tx_buff[3] = 0x04;    // 电池相关指令

                    uart_data.tx_buff[4] = 0x04;   // 电池信息应答

                    if(CHARGE_STA == get_sys_state()){
                        uart_data.tx_buff[5] = 0x01;    // 充电中
                    }
                    else{
                        uart_data.tx_buff[5] = 0x02;    // 充电完毕     
                    }

                    crc = crc16_compute(uart_data.tx_buff, 6);

                    uart_data.tx_buff[6] = crc>>8;
                    uart_data.tx_buff[7] = crc&0xff;

                    uartx_send_data(8);
                   // printf(" charge sta req \r\n ");
                   //
                    break;
                }
                default:{

                    break;
                }
            }
        }
        default:{

            break;
        }
    }
}

